package com.cxm.helper.aspect;

import cn.hutool.json.JSONUtil;
import com.cxm.helper.annotation.LogApi;
import com.cxm.helper.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @author chenximeng
 */
@Slf4j
@Aspect
@Component
public class RequestLogAspect {
    static final String LOG_FORMAT = "\n" +
            "请求者IP  : {}\n" +
            "请求地址  : {}\n" +
            "请求时间  : {}\n" +
            "请求类型  : {}\n" +
            "请求方法  : {}\n" +
            "请求参数  : {}\n" +
            "返回对象  : {}\n" +
            "总共耗时  : {} 毫秒\n";

    @Pointcut("execution(public * com.cxm.helper.controller..*.*(..))")
    public void apiLog() {
    }

    @Around("apiLog()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        boolean throwEx = false;
        Object obj = null;
        long before = System.currentTimeMillis();
        try {
            obj = point.proceed();
        } catch (Throwable throwable) {
            throwEx = true;
            throw throwable;
        } finally {
            try {
                MethodSignature signature = (MethodSignature) point.getSignature();
                LogApi logApi = AnnotationUtils.findAnnotation(signature.getMethod(), LogApi.class);
                if (logApi == null) {
                    logApi = AnnotationUtils.findAnnotation(signature.getDeclaringType(), LogApi.class);
                }
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

                if (attributes != null) {
                    HttpServletRequest request = attributes.getRequest();
                    //请求者IP
                    String ip = HttpUtil.getRemoteIp(request);
                    //请求地址
                    String address = request.getRequestURL().toString();
                    //请求类型
                    String requestType = request.getMethod();
                    //请求方法
                    String method = point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName();

                    String params = "***";
                    String returnMsg = "***";
                    LogApi.LogLevel type = logApi != null ? logApi.level() : LogApi.LogLevel.ALL;
                    if (type == LogApi.LogLevel.ALL) {
                        //请求参数
                        params = Arrays.toString(point.getArgs());
                        //返回对象
                        if (obj != null) {
                            returnMsg = JSONUtil.toJsonStr(obj);
                        } else if (throwEx) {
                            returnMsg = "接口异常";
                        } else {
                            returnMsg = "void";
                        }
                    }

                    log.info(LOG_FORMAT
                            , ip
                            , address
                            , System.currentTimeMillis()
                            , requestType
                            , method
                            , params
                            , returnMsg
                            , System.currentTimeMillis() - before
                    );
                }
            } catch (Exception e) {
                log.warn("RequestLogAspect异常", e);
            }
        }

        return obj;
    }

}
